import { Injectable } from "@angular/core";

import { WebSocketEnum } from '../model/parameters';
import { IProvider } from "../provider.interface";
import { LoggerService, LoggerInfo } from '../../logger/logger.service';
//var api = require('../ref/pilot-api.js');
/// <reference path='../ref/pilot-api.d.ts' />
//import {PilotCommunicator, } from "./../ref/pilot-api";
import { PProxyRequest, PQNSContext } from '../ref/pilot-api';
import { Http } from '@angular/http';

@Injectable()
export class WebSocketProvider implements IProvider {
    websocketUrl: string;
    pilot: any;
    servicePara: any;
    logger: LoggerService;
    constructor(websocketUrl: string, pilot: any, serviceParas: any) {
        this.websocketUrl = websocketUrl;
        this.pilot = pilot;
        this.servicePara = serviceParas;
        this.logger = new LoggerService();
    }

    set(http: Http): void {

    }

    // start =====  general functions of RESTFul & Websocket & Mock =====
    query(paras: any, sucCallback: Function, failCallback: Function): void {
        try {
            this._EXECUTE(paras, this.servicePara.query, sucCallback, failCallback);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.query", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    get(paras: any, sucCallback: Function, failCallback: Function): void {
        try {
            this._EXECUTE(paras, this.servicePara.get, sucCallback, failCallback);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.get", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    add(paras: any, sucCallback: Function, failCallback: Function): void {
        try {
            this._EXECUTE(paras, this.servicePara.post, sucCallback, failCallback);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.add", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    update(paras: any, sucCallback: Function, failCallback: Function): void {
        try {
            this._EXECUTE(paras, this.servicePara.put, sucCallback, failCallback);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.update", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    delete(paras: any, sucCallback: Function, failCallback: Function): void {
        try {
            this._EXECUTE(paras, this.servicePara.delete, sucCallback, failCallback);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.delete", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }
    // end ===== general functions of RESTFul & Websocket =====  

    // start ===== special functions of Websocket =====
    invokeProxy(paras: any, sucCallback: Function, failCallback: Function): void {
        try {
            this._EXECUTE(paras, this.servicePara, sucCallback, failCallback);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.invokeProxy", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    stopRequest(requestId: number, sucCallback: Function, failCallback: Function): void {
        try {
            this._STOP(requestId);
            sucCallback("stop request successed - requestId : " + requestId);
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.stopRequest", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    stopAllRequests(sucCallback: Function, failCallback: Function): void {
        try {
            this._STOPALL();
            sucCallback("stop all requests successed");
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.stopAllRequests", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    closeConnection(sucCallback: Function, failCallback: Function): void {
        try {
            this._DISCONNECT();
            sucCallback("close connection successed");
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.closeConnection", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }

    openConnection(token: string, sucCallback: Function, failCallback: Function): void {
        try {
            this._CONNECT(token);
            sucCallback("open connection successed");
        } catch (error) {
            this.logger.error(new LoggerInfo("framework/provider/WebSocketProvider.openConnection", "execution failed", error));
            if (failCallback) {
                failCallback(error);
            }
        }
    }
    // end ===== special functions of Websocket =====

    private _EXECUTE(para: any, serviceParas: any, sucCallback: Function, failCallback: Function): void {
        let listener: any = {
            onMessage: sucCallback,
            onError: failCallback,
            onStart: function () { console.log("start operation"); },
            onEnd: function () { console.log("end operation"); }
        }
        let requestId: number = new Date().getTime();
        switch (serviceParas.method) {
            case WebSocketEnum.query: {
                let context: any = this._GeneratePQNSContext(para.common, serviceParas.common, requestId);
                this.pilot.query(context, listener);
                break;
            }
            case WebSocketEnum.subscribe: {
                let context: any = this._GeneratePQNSContext(para.common, serviceParas.common, requestId);
                this.pilot.subscribe(context, listener);
                break;
            }
            case WebSocketEnum.qns: {
                let context: any = this._GeneratePQNSContext(para.common, serviceParas.common, requestId);
                this.pilot.qns(context, listener);
                break;
            }
            case WebSocketEnum.publish: {
                this.pilot.publish(para.publish.BO, para.publish.msgDef);
                break;
            }
            case WebSocketEnum.invokeProxy: {
                let classname: string = serviceParas.invokeProxy.className;
                let method: string = serviceParas.invokeProxy.method;
                let proxyRequest: any = new PProxyRequest(requestId, classname, method, JSON.parse(para.invokeProxy.parameters));
                this.pilot.invokeProxy(proxyRequest, listener);
                break;
            }
            default: {
                let context: any = this._GeneratePQNSContext(para.common, serviceParas.common, requestId);
                this.pilot.query(context, listener);
                break;
            }
        }
    }

    private _GeneratePQNSContext(para: any, serviceParas: any, requestId: number): any {
        let context: any;
        let fullSql: string = serviceParas.fullSQL;
        let selector: string = serviceParas.selector;
        let topic: string = serviceParas.topic;
        if (fullSql !== undefined && fullSql !== "") {
            context = new PQNSContext(fullSql, requestId);
        }
        else {
            if (selector === undefined || selector === "") {
                selector = "*";
            } else { }
            let sql: string = `select ${selector} from ${topic} where ${para.Condition}`;
            context = new PQNSContext(sql, requestId);
        }
        return context;
    }

    private _CONNECT(token: string): void {
        this.pilot.connect(this.websocketUrl, token);
    }

    private _DISCONNECT(): void {
        this.pilot.disconnect();
    }

    private _STOP(requestId): void {
        let context = new PQNSContext(null, requestId);
        this.pilot.cancelSubscription(context);
    }

    private _STOPALL(): void {
        this.pilot.cancelAllSubscriptions();
    }
}